package com.fezs.redis.config;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.fezs.redis.aop.RedissonLimiterAop;
import com.fezs.redis.aop.RedissonLockAop;
import com.fezs.redis.config.properties.RedissonProperties;
import com.fezs.redis.handler.KeyPrefixHandler;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.spring.cache.CacheConfig;
import org.redisson.spring.cache.RedissonSpringCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfig {

    private static final String REDIS_PROXY = "redis://";

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${spring.redis.password:}")
    private String password;

    @Autowired
    private RedissonProperties redissonProperties;

    @Bean
    @ConditionalOnMissingBean
    public RedissonClient redissonClient() throws IOException {
        Config config = Config.fromYAML(new ClassPathResource("redisson.yml").getInputStream());
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setAddress(REDIS_PROXY + host + ":" + port);
        if (StrUtil.isNotEmpty(password)) {
            singleServerConfig.setPassword(password);
        }
        // 设置前缀
        singleServerConfig.setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()));
        return Redisson.create(config);
    }

    @Bean
    @ConditionalOnMissingBean
    public RedissonLockAop redissonLockAop() {
        return new RedissonLockAop();
    }

    @Bean
    @ConditionalOnMissingBean
    public RedissonLimiterAop redissonLimiterAop() {
        return new RedissonLimiterAop();
    }

    /**
     * 整合spring-cache
     */
    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
        if (CollUtil.isEmpty(cacheGroup)) {
            return new RedissonSpringCacheManager(redissonClient);
        }
        Map<String, CacheConfig> config = new ConcurrentHashMap<>();
        for (RedissonProperties.CacheGroup group : cacheGroup) {
            CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
            cacheConfig.setMaxSize(group.getMaxSize());
            config.put(group.getGroupId(), cacheConfig);
        }
        return new RedissonSpringCacheManager(redissonClient, config);
    }

}
